#study8从 函数的创建 到 函数的定义与调用 到 变量的作用域 再到 递归函数

#函数的定义、调用与参数的传递
def ca(a,b):#定义函数，参数；a、b为形式参数（形参）
    c=a+b#函数的运算法则
    return c#结束这个函数且这个被定义的函数的输出的值：c
r=ca(10,20)#10、20称为实际参数（实参），这个例子是位置传递
r1=ca(b=10,a=20)#关键字传递
print(r,r1)

#实参与形参赋值的关系：如果是不可变对象，对形参赋值不会影响实参的值；如果是可变对象，对形参赋值会影响实参的值(也就是id不会改变)
x1,x2=100,[123,456,789]
def fun(xing1,xing2):
    xing1=150
    xing2.append(10)
fun(x1,x2)
print(x1,x2)

#函数的返回值
#如果不需用给输入的数据提供结果，可以不写return
#函数返回值如果是一个，则直接返回类型
#函数返回多个值的时候，结果为元组

#函数的参数定义
def fun1(a,b=10):#b因为被赋值，所以叫做默认值形参
    print(a,b)

fun1(150)#按位置把a赋值为30
fun1(80,70)#b被重新赋值为70

#个数可变的位置参数
def f1(*n):#’*‘是重点
    print(n)
f1('hello,world!')
f1(123,456)
f1('abc',789,'def')#这样得到的是元组
#个数可变的关键字形参
def f2(**n):#’**‘得到的是字典
    print(n)
f2(a=123,b=456,c=789)
def test1(*test1,**test2):
    pass#这样不会报错，但两个参数反过来会报错

#总结与一些巧妙应用：
l=[11,22,33]
def f3(a,b,c):
    print('a=',a,'b=',b,'c=',c)
f3(*l)#‘*‘让列表的每个元素都转换为位置实参
f3(c=4,a=5,b=6)#关键字传递
d={'a':1,'b':2,'c':3}
f3(**d)
#上面是关于实参的，下面是关于形参的
def f4(a,b=10):#b是默认值形参
    print('a=',a,'b=',b)
def f5(*m):#个数可变的位置形参
    print(m)
f5(11,22,33)#得到的结果是元组
def f6(**a):
    print(a)
f6(a=11,b=22,c=33)#得到的结果是字典
def f7(a,b,*,c,d):#‘*’之后的参数只能关键字传递
    print('a=',a,'b=',b,'c=',c,'d=',d)
f7(1,2,c=4,d=3)#部分位置传递，部分关键字传递（c和d），要让cd只能关键字传递需要在f7的c的前面加一个‘*’
#顺序问题
def f7(a,b,*,c,d,**e):
    pass
def f8(a,b=10,*c,**d):
    pass

#变量的作用域
#函数内部的变量仅作用于函数的内部，无法在函数外部进行提取，相当于局部变量
#函数的外部变量可以在函数内部进行提取,称为全局变量
#如果想在函数内部定义的变量在函数外部也可以使用，可以使用内置函数global
def f9():
    global y1
    y1=10
    print(y1)
f9()
print(y1)

#递归函数
jg=1
def jiecheng(bl):#比如阶乘就可以用递归
    if bl == 1:
        return 1
    else:
        return bl*jiecheng(bl-1)
i1=int(input('输入一个数'))
print(jiecheng(i1))

def fbnqsl(a):#再来个斐波那契数列
    if a == 1:
        return 1
    elif a== 2:
        return 1
    else:
        return fbnqsl(a-1)+fbnqsl(a-2)
print(fbnqsl(i1))